﻿using System;
using System.Diagnostics;
using log4net;
using OdsServer;
using OdsServer.Common;
using OdsServer.Common.Enum;
using System.Configuration;
using System.Threading;
using OdsServer.Device;

namespace OdsServerConsole
{
    sealed class ServerConsole
    {
        private static readonly ILog log        = LogManager.GetLogger(typeof(ServerConsole));
        private static IServerService server    = null;
        private static readonly IntPtr hWnd     = Process.GetCurrentProcess().MainWindowHandle;
        private static volatile bool threadQuit = false;
        private static IDeviceInteropAI device  = null;
        
        public static void Main()
        {
#if GC_PROFILE
            // register garbage collection events
            // 10 for Gen0 to Gen9 - 1 for LOH to notify each GC occurance
            GC.RegisterForFullGCNotification(10, 1);
#endif
            OdsServerRepository.Initialize();
            DeviceRepository.Initialize();

            // init log4net
            log4net.Config.XmlConfigurator.Configure();
            log.Info("Server Console started");

#if GC_PROFILE
            log.Info("GC Profiling is active");

            Thread gcLoggerThread   = new Thread(new ThreadStart(GCEventLoggerThread));
            gcLoggerThread.Priority = ThreadPriority.Lowest;

            gcLoggerThread.Start();
#endif

            Process.GetCurrentProcess().EnableRaisingEvents = true;
            Process.GetCurrentProcess().PriorityClass       = ProcessPriorityClass.AboveNormal;

            Console.CancelKeyPress += new ConsoleCancelEventHandler(ConsoleExit);

            device = DeviceRepository.GetDefaultDeviceInteropAI();

            OdsServerRepository.SetProcessingDeviceAI(device);

            server = OdsServerRepository.GetServer();
            
            OdsServerConfiguration config   = OdsServerConfiguration.GetInstance();
            SetupParameters param           = config.GetSetupParameters();
            param.parentWindowHanlde        = hWnd;
            server.SetupParameters          = param;

            server.Start();

            while (Console.ReadKey(true).Key != ConsoleKey.Escape) 
            {
                Thread.Sleep(5);
            }

            threadQuit = true;

#if GC_PROFILE
            gcLoggerThread.Join();
#endif

            server.Stop();
        }

        private static void ConsoleExit(object sender, ConsoleCancelEventArgs e)
        {
            if (server != null)
                server.Stop();

            Process.GetCurrentProcess().CloseMainWindow();
        }

#if GC_PROFILE
        private static void GCEventLoggerThread()
        {
            GCNotificationStatus status = GCNotificationStatus.Failed;
            Stopwatch timer             = new Stopwatch(); 

            while (!threadQuit)
            {
                status = GC.WaitForFullGCApproach(100);

                if (status == GCNotificationStatus.Succeeded)
                {
                    timer.Reset();
                    timer.Start();

                    log.Debug("FullGC initiated.");

                    status = GC.WaitForFullGCComplete();

                    timer.Stop();

                    if (status == GCNotificationStatus.Succeeded)
                        log.DebugFormat("FullGC completed in {0} ms.", timer.ElapsedMilliseconds);
                }
            }
        }
#endif
    }
}